#ifndef GEOMETRY_POINT_HPP
#define GEOMETRY_POINT_HPP

#include <cmath>

/// Represents a point in a 2-D coordinate system.
template <class T>
struct Point
{
    T x, y;
    Point() : x(0), y(0) { }
    Point(T x_, T y_) : x(x_), y(y_) { }
    bool operator == (const Point<T> &other) const
    {
        return x == other.x && y == other.y; 
    }
};

/// Returns the center of two points.
template <class T>
Point<T> center(const Point<T> &P1, const Point<T> &P2)
{
    return Point((P1.x + P2.x) / 2, (P1.y + P2.y) / 2);
}

/// Returns the mid-point P of line segment P1P2, such that P1P / P1P2 = r.
template <class T>
Point<T> midPoint(const Point<T> &P1, const Point<T> &P2, T r)
{
    T x = r*P2.x + (1-r)*P1.x;
    T y = r*P2.y + (1-r)*P1.y;
    return Point<T>(x, y);
}

/// Find the ratio r such that for a given line segment P1P2 and a point P on
/// the extended line of the line segment, P1P / P1P2 = r.
template <class T>
T invMidPoint(const Point<T> &P, const Point<T> &P1, const Point<T> &P2)
{
    T x1 = P1.x, y1 = P1.y, x2 = P2.x, y2 = P2.y, x = P.x, y = P.y;
    T det = (x2-x1)*(x2-x1) + (y2-y1) *(y2-y1);
    if (det == 0)
        return 0;
    else
        return ((x-x1)*(x2-x1)+(y-y1)*(y2-y1)) / det;
}

/// Returns the Euclidean distance between two points.
template <class T>
T distance(const Point<T> &P1, const Point<T> &P2)
{
    return std::sqrt((P1.x-P2.x)*(P1.x-P2.x) + (P1.y-P2.y)*(P1.y-P2.y));
}

/// Returns the Manhattan distance between two points.
template <class T>
T manhattan(const Point<T> &P1, const Point<T> &P2)
{
    return std::abs(P1.x - P2.x) + std::abs(P1.y - P2.y);
}

#if 0
/// Transforms a point.
Point transform(const Point &p, const Transformation &t)
{
    return Point(
        t.a[0][0]*p.x + t.a[0][1]*p.y + t.a[0][2],
        t.a[1][0]*p.x + t.a[1][1]*p.y + t.a[1][2]);
}
#endif

#endif /* GEOMETRY_POINT_HPP */
